package org.dubnation.car.service.impl;

import org.dubnation.base.constants.SystemConstants;
import org.dubnation.base.enums.ResponseCode;
import org.dubnation.base.exception.BusinessException;
import org.dubnation.car.domain.CarType;
import org.dubnation.car.mapper.CarTypeMapper;
import org.dubnation.car.service.ICarTypeService;
import org.dubnation.base.service.impl.BaseServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhu
 * @since 2023-11-01
 */
@Service
public class CarTypeServiceImpl extends BaseServiceImpl<CarType> implements ICarTypeService {

    @Autowired(required = false)
    private CarTypeMapper mapper;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private CarTypeMapper carTypeMapper;

    /**
     * 查询大批量数据
     * 序列化：把对象转换为通用的二进制数的过程
     *       redis中存储的一般都是字符串，将对象存储到redis中要将其转换为字符串，字符串.getBytes()得到二进制数；
     * 反序列化：将二进制数转换为对象的过程
     * 如果要将一个对象存储到redis中，需要将该对象序列化
     * @return
     */
//    @Cacheable(cacheNames = SystemConstants.TYPE_TREE, key = "'ALL'")  //将方法的返回值写入缓存
    @Override
    public List<CarType> getTreeData() {
//        //1.先从Redis缓存中查询
//        List<CarType> carTypeList = (List<CarType>) redisTemplate.opsForValue().get(SystemConstants.TYPE_TREE);
//        //2.如果Redis中没有，再到数据库中查询并返回，将数据存放在Redis缓存中
//        if (carTypeList == null){
//            carTypeList = queryDataLoop();
//            redisTemplate.opsForValue().set(SystemConstants.TYPE_TREE, carTypeList);
//        }
//        //3.下次查询不走数据库，直接从缓存中查询到后返回
//        return carTypeList;
        return queryDataLoop();
    }

    /**
     * 获取车辆类型--仅仅是父类型
     * @return
     */
    @Override
    public List<CarType> queryTypes() {
        return mapper.getTypes(0L);
    }

    /**
     * 循环查询--
     * 查询所有车辆类型数据，并把其封装成树形结构对象
     * @return
     */
    private List<CarType> queryDataLoop() {
        //1.查询所有车辆类型数据，得到一个List集合
        List<CarType> allTypes = mapper.queryAll();
        HashMap<Long, CarType> typeMap = new HashMap<>();
        //2.创建一个用于返回树形结构对象的List
        List<CarType> resultList = new ArrayList<>();
        //3.遍历开始获取的所有车辆类型List集合，将List中的每一个对象都存储到Map中
        for (CarType allType : allTypes) {
            typeMap.put(allType.getId() ,allType);
        }
        for (CarType allType : allTypes) {
            //4.判断如果车辆类型的pid为0，将其存储到返回的结果集合中，如果pid不为0，查到它的父类型并将其放到父类型的children属性中
            if (allType.getPid() == 0L) resultList.add(allType);
            else {
                CarType parent = mapper.queryByPid(allType.getPid());
                CarType carType = typeMap.get(parent.getId()); //获取当前车辆类型的父类型
                carType.getChildren().add(allType);
            }
        }
        return resultList;
    }

    /**
     * 删除车辆类型
     * @param typeId
     */
    @Override
    @Transactional
    @CacheEvict(cacheNames = SystemConstants.Redis.CAR_TYPE_TREE, key = "'ALL'")
    public void deleteType(Long typeId) {
        //1.根据车辆类型数据的description字段获取当前类型数据的所有子类型
        List<CarType> carTypeList = (List<CarType>) redisTemplate.opsForValue().get(SystemConstants.Redis.CAR_TYPE_TREE);
        try {
            if (Objects.isNull(carTypeList)){
                carTypeList = carTypeMapper.queryAll();
            }
            redisTemplate.delete(SystemConstants.Redis.CAR_TYPE_TREE);
            CarType deleteCarType = null;
            List<Long> deleteTypeIds = new ArrayList<>();
            for (CarType carType : carTypeList) {
                //获取每条数据的description字段, 将与该条数据description相关的数据抽取出来
                if (carType.getId().equals(typeId)){
                    //获取该条数据
                    deleteCarType = carType;
                }
                if (deleteCarType != null){
                    if (carType.getDescription().contains(deleteCarType.getDescription())){
                        //获取到该条数据的所有子类型数据
                        deleteTypeIds.add(carType.getId()); //将需要删除的车辆类型数据存储到集合中
                    }
                }
            }
            //2.删除数据
            carTypeMapper.batchDelete(deleteTypeIds);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ResponseCode.RESPONSE_CODE_4000033);
        }
        redisTemplate.delete(SystemConstants.Redis.CAR_TYPE_TREE); //延时双删
    }

    /**
     * 在对数据库数据修改之后需要删除缓存中的数据，使缓存数据更新
     * @param carType
     */
    @CacheEvict(cacheNames = SystemConstants.TYPE_TREE, key = "'ALL'")  //删除缓存，将缓存中的数据删除
    @Override
    public void insert(CarType carType) {
        super.insert(carType);
    }

    @CacheEvict(cacheNames = SystemConstants.TYPE_TREE, key = "'ALL'")
    @Override
    public void update(CarType carType) {
        super.update(carType);
    }

    @CacheEvict(cacheNames = SystemConstants.TYPE_TREE, key = "'ALL'")
    @Override
    public void delete(Serializable id) {
        super.delete(id);
    }
}
